﻿#region License, Terms and Conditions
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
#endregion

using System;
using System.Collections.Generic;
using System.Web;

namespace raya.Library
{
    public class Model 
    {
        private Dictionary<string, HashSet<string>> dep_map = new Dictionary<string, HashSet<string>>();
        private bool isDisposed;
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

       ~Model()
       {
            Dispose(false);
       }

       protected void Dispose(bool disposedStatus)
       {
            if (!isDisposed)
            {
                isDisposed = true;
                if (disposedStatus)
                {
                    foreach (var pair in dep_map)
                    {
                        var newdeps = pair.Value;
                        HttpRuntime.Cache.Insert(pair.Key, newdeps);
                    }
                }
            }
       }

        protected bool TryGetCache(string type, string id, out object value)
        {
            if (RayaSettings.Enable_caching.Equals("false"))
            {
                value = null;
                return false;
            }

            string key = type + "_res:" + id;
            
            // anything in cache
            object data = HttpRuntime.Cache.Get(key);

            // yes, return cached entry
            if (data == null)
            {
                value = null;
                return false;
            }
            value = data;
            return true;
        }

        protected string Insert(string type, string id, object value)
        {

            if (value == null || RayaSettings.Enable_caching.Equals("false"))
            {
                return null;
            }

            string key = OAuthUtil.md5(type + "_res:" + id);
            // add with no sliding or absolute expiration
            // cache dependencies are manually handled
            HttpRuntime.Cache.Insert(key,value);

            return key;
        }

        public void add_dependency(string type, string id, string hashkey)
        {
            if (RayaSettings.Enable_caching.Equals("false"))
            {
                return;
            }
            // if null then just add independent cache entry
            string cacheKey = OAuthUtil.md5(hashkey ?? (type + "_res:" + id));
            string hash = OAuthUtil.md5(type + "_deps:" + id);
            if (!dep_map.ContainsKey(hash))
            {
                // check if dep already cached previously
                var deps = HttpRuntime.Cache.Get(hash);
                if (deps != null)
                {
                    dep_map.Add(hash, (HashSet<string>)deps);
                }
                else
                {
                    dep_map.Add(hash, new HashSet<string>());
                }
            }
            dep_map[hash].Add(cacheKey);
        }

        public void invalidate_dependency(string type, string id)
        {
            if (RayaSettings.Enable_caching.Equals("false"))
            {
                return;
            }
            string hash = OAuthUtil.md5(type + "_deps:" + id);
            if (!dep_map.ContainsKey(hash))
            {
                // check if dep already cached previously
                var deps = HttpRuntime.Cache.Get(hash);
                if (deps != null)
                {
                    dep_map.Add(hash, (HashSet<string>)deps);
                    HttpRuntime.Cache.Remove(hash);
                }
                else
                {
                    dep_map.Add(hash, new HashSet<string>());
                }
            }
            // remove affected cached entries
            HashSet<string> keys = dep_map[hash];
            foreach (var key in keys)
            {
                HttpRuntime.Cache.Remove(key);
            }
            // remove dependency
            dep_map.Remove(hash);

        }
    }
}